﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CatClient.Util;

namespace CatClient.Fusing
{
    // Token: 0x0200005F RID: 95
    internal abstract class FuseStatistics : IDisposable
    {
        // Token: 0x14000001 RID: 1
        // (add) Token: 0x06000303 RID: 771 RVA: 0x0000AC88 File Offset: 0x00008E88
        // (remove) Token: 0x06000304 RID: 772 RVA: 0x0000ACC0 File Offset: 0x00008EC0
        public event EventHandler OnFused;

        // Token: 0x14000002 RID: 2
        // (add) Token: 0x06000305 RID: 773 RVA: 0x0000ACF8 File Offset: 0x00008EF8
        // (remove) Token: 0x06000306 RID: 774 RVA: 0x0000AD30 File Offset: 0x00008F30
        public event EventHandler OnRecoveried;

        // Token: 0x170000D3 RID: 211
        // (get) Token: 0x06000307 RID: 775 RVA: 0x0000AD65 File Offset: 0x00008F65
        // (set) Token: 0x06000308 RID: 776 RVA: 0x0000AD6D File Offset: 0x00008F6D
        public bool Running { get; set; }

        // Token: 0x170000D4 RID: 212
        // (get) Token: 0x06000309 RID: 777
        public abstract FuseType Type { get; }

        // Token: 0x170000D5 RID: 213
        // (get) Token: 0x0600030A RID: 778
        public abstract int Duration { get; }

        // Token: 0x170000D6 RID: 214
        // (get) Token: 0x0600030B RID: 779
        public abstract long Threshold { get; }

        // Token: 0x0600030C RID: 780 RVA: 0x0000AD76 File Offset: 0x00008F76
        protected FuseStatistics()
        {
            this.Statistics = new ConcurrentDictionary<long, long>();
        }

        // Token: 0x0600030D RID: 781 RVA: 0x0000AD94 File Offset: 0x00008F94
        public void Increment()
        {
            if (!this.Running)
            {
                return;
            }
            long currentTimeMinute = MilliSecondTimer.CurrentTimeMinute;
            this.Statistics.AddOrUpdate(currentTimeMinute, (long key) => 1L, (long key, long old) => old + 1L);
        }

        // Token: 0x0600030E RID: 782 RVA: 0x0000ADFB File Offset: 0x00008FFB
        public void Increment(object value)
        {
            if (!this.Running)
            {
                return;
            }
            if (this.IncValueProcess(value))
            {
                this.Increment();
            }
        }

        // Token: 0x0600030F RID: 783 RVA: 0x0000AE15 File Offset: 0x00009015
        protected virtual bool IncValueProcess(object value)
        {
            LogInfoWriter.GetInstance("Cat", 0, LogInfoWriter.LogLayout.Default).Warn(string.Format("{0} called Increment method with value parameter, but haven't rewrite IncValueProcess method.", base.GetType().Name));
            return false;
        }

        // Token: 0x06000310 RID: 784 RVA: 0x0000AE40 File Offset: 0x00009040
        public virtual void Start()
        {
            if (this.Running)
            {
                LogInfoWriter.GetInstance("Cat", 0, LogInfoWriter.LogLayout.Default).Warn(string.Format("[{0}] fuse statistics is running, can not running mutiple instance!", base.GetType().Name));
                return;
            }
            object runningLocker = this.RunningLocker;
            lock (runningLocker)
            {
                if (this.Running)
                {
                    LogInfoWriter.GetInstance("Cat", 0, LogInfoWriter.LogLayout.Default).Warn(string.Format("[{0}] fuse statistics is running, can not running mutiple instance!", base.GetType().Name));
                }
                else
                {
                    try
                    {
                        Task checkTask = this.CheckTask;
                        if (checkTask != null)
                        {
                            checkTask.Dispose();
                        }
                        CancellationTokenSource checkCts = this.CheckCts;
                        if (checkCts != null)
                        {
                            checkCts.Dispose();
                        }
                    }
                    catch
                    {
                    }
                    this.CheckCts = new CancellationTokenSource();
                    this.CheckTask = new Task(new Action(this.Check), this.CheckCts.Token);
                    try
                    {
                        this.CheckTask.Start();
                        this.Running = true;
                        this.Fused = false;
                    }
                    catch (Exception exception)
                    {
                        LogInfoWriter.GetInstance("Cat", 0, LogInfoWriter.LogLayout.Default).Error(string.Format("[{0}] start fuse check task failed!", base.GetType().Name), exception);
                        this.Running = false;
                        this.Fused = true;
                    }
                }
            }
        }

        // Token: 0x06000311 RID: 785 RVA: 0x0000AF9C File Offset: 0x0000919C
        public virtual Task Stop()
        {
            this.Statistics.Clear();
            try
            {
                this.CheckCts.Cancel();
            }
            catch (ObjectDisposedException)
            {
            }
            catch (Exception exception)
            {
                LogInfoWriter.GetInstance("Cat", 0, LogInfoWriter.LogLayout.Default).Error(string.Format("[{0}] error occured when cancel task!", base.GetType().Name), exception);
            }
            this.Running = false;
            return this.CheckTask;
        }

        // Token: 0x06000312 RID: 786 RVA: 0x0000B018 File Offset: 0x00009218
        protected virtual void Fuse()
        {
            this.Fused = true;
            string arg = string.Join(", ", from kvp in this.Statistics
                                           select new DateTime(1970, 1, 1).Add(TimeZoneInfo.Local.BaseUtcOffset).Add(TimeSpan.FromMinutes((double)kvp.Key)).ToString("HH:mm") + " -> " + kvp.Value);
            LogInfoWriter.GetInstance("Cat", 0, LogInfoWriter.LogLayout.Default).Warn(string.Format("[FUSE] {0} fused! statics: [{1}]", base.GetType().Name, arg));
            EventHandler onFused = this.OnFused;
            if (onFused == null)
            {
                return;
            }
            onFused(this, EventArgs.Empty);
        }

        // Token: 0x06000313 RID: 787 RVA: 0x0000B0A0 File Offset: 0x000092A0
        protected virtual void Recovery()
        {
            this.Fused = false;
            this.Statistics.Clear();
            EventHandler onRecoveried = this.OnRecoveried;
            if (onRecoveried != null)
            {
                onRecoveried(this, EventArgs.Empty);
            }
            LogInfoWriter.GetInstance("Cat", 0, LogInfoWriter.LogLayout.Default).Warn(string.Format("[RECOVERY] {0} recoveried!", base.GetType().Name));
        }

        // Token: 0x06000314 RID: 788 RVA: 0x0000B0FC File Offset: 0x000092FC
        protected virtual void Check()
        {
            for (; ; )
            {
                MilliSecondTimer.SleepToNextMinute(3000);
                try
                {
                    if (this.CheckCts.IsCancellationRequested)
                    {
                        break;
                    }
                }
                catch (ObjectDisposedException)
                {
                    break;
                }
                catch (NullReferenceException)
                {
                    break;
                }
                catch (Exception exception)
                {
                    LogInfoWriter.GetInstance("Cat", 0, LogInfoWriter.LogLayout.Default).Error(string.Format("[{0}]error occur when check task canceled!", base.GetType().Name), exception);
                    break;
                }
                long minute = MilliSecondTimer.CurrentTimeMinute - 1L;
                if (this.Fused)
                {
                    try
                    {
                        if (this.RecoveryCheck(minute))
                        {
                            this.Recovery();
                        }
                        goto IL_DF;
                    }
                    catch (Exception exception2)
                    {
                        LogInfoWriter.GetInstance("Cat", 0, LogInfoWriter.LogLayout.Default).Error(string.Format("[{0}]error occur when check recovery!", base.GetType().Name), exception2);
                        goto IL_DF;
                    }
                    goto IL_A3;
                }
                goto IL_A3;
                IL_DF:
                this.StatisticsClean(minute);
                continue;
                IL_A3:
                try
                {
                    if (this.FuseCheck(minute))
                    {
                        this.Fuse();
                    }
                }
                catch (Exception exception3)
                {
                    LogInfoWriter.GetInstance("Cat", 0, LogInfoWriter.LogLayout.Default).Error(string.Format("[{0}]error occur check fuse!", base.GetType().Name), exception3);
                }
                goto IL_DF;
            }
        }

        // Token: 0x06000315 RID: 789 RVA: 0x0000B234 File Offset: 0x00009434
        protected virtual bool RecoveryCheck(long minute)
        {
            long num = 0L;
            for (int i = 0; i < this.Duration; i++)
            {
                long num2;
                if (this.Statistics.TryGetValue(minute - (long)i, out num2))
                {
                    num += num2;
                }
            }
            return num < this.Threshold;
        }

        // Token: 0x06000316 RID: 790 RVA: 0x0000B278 File Offset: 0x00009478
        protected virtual bool FuseCheck(long minute)
        {
            long num = 0L;
            for (int i = 0; i < this.Duration; i++)
            {
                long num2;
                if (this.Statistics.TryGetValue(minute - (long)i, out num2))
                {
                    num += num2;
                }
            }
            return num >= this.Threshold;
        }

        // Token: 0x06000317 RID: 791 RVA: 0x0000B2BC File Offset: 0x000094BC
        protected void StatisticsClean(long minute)
        {
            foreach (long key2 in from key in this.Statistics.Keys
                                  where key <= minute - (long)this.Duration
                                  select key)
            {
                long num;
                this.Statistics.TryRemove(key2, out num);
            }
        }

        // Token: 0x06000318 RID: 792 RVA: 0x0000B33C File Offset: 0x0000953C
        public void Dispose()
        {
            try
            {
                this.CheckTask.Dispose();
            }
            catch
            {
            }
        }

        // Token: 0x04000157 RID: 343
        protected object RunningLocker = new object();

        // Token: 0x04000158 RID: 344
        protected ConcurrentDictionary<long, long> Statistics;

        // Token: 0x04000159 RID: 345
        protected Task CheckTask;

        // Token: 0x0400015A RID: 346
        protected CancellationTokenSource CheckCts;

        // Token: 0x0400015B RID: 347
        public bool Fused;
    }
}
